package com.hcss.picture.controller;

import cn.hutool.core.lang.Pair;
import com.alibaba.fastjson.JSON;
import com.github.pagehelper.PageInfo;
import com.hcss.common.base.BaseClass;
import com.hcss.common.util.*;
import com.hcss.common.util.excel.ImageUtils;
import com.hcss.common.vo.ResultMsg;
import com.hcss.common.vo.Results;
import com.hcss.paging.constant.PagingConstant;
import com.hcss.paging.constant.QueryType;
import com.hcss.paging.model.QuerySchema;
import com.hcss.picture.constant.PictureConstant;
import com.hcss.update.model.UpdateSchema;
import com.hcss.util.AjaxResult;
import com.hcss.util.BeanCopyUtil;
import com.hcss.util.EmptyUtil;
import com.hcss.util.ListUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.ArrayUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;
import com.hcss.picture.model.Picture;
import com.hcss.picture.model.par.PicturePar;
import com.hcss.picture.service.PictureService;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.*;
import java.util.concurrent.*;

/**
 * @描述: 图片的model层 功能模块
 * @作者: guoxia
 * @创建日期: 2023-03-01 11:55:22
 */
@Api(tags = "图片检测模块")
@Slf4j
@RestController
@RequestMapping("picture")
public class PictureController {
	@Autowired
	private PictureService pictureService;
	@Autowired
	RedisTemplate redisTemplate;

	private String newKeyName;

	/**
	 * 查询使用的schema
	 * 使用.withQueryFields(QueryType type, String... queryFileds)插入查询规则和查询字段
	 */
	static QuerySchema querySchema=new QuerySchema( Picture.class );

	static {
		querySchema.withQueryFields( QueryType.eq,"pictureType","ifDelete","optiorName" )
				.withQueryFields( QueryType.like,"pictureName" );
	}

	/**
	 * 更新插入的schema，用于鉴定数据的安全性
	 */
	static UpdateSchema updateSchema=new UpdateSchema( Picture.class,null,null );

	/**
	 * Picture数据列表页面
	 *
	 * @return
	 */
	@GetMapping("listPage")
	public ModelAndView listPage( ) {
		return new ModelAndView( "/picture/picture-listPage" );
	}

	/**
	 * 新增页面
	 *
	 * @return
	 */
	@GetMapping("/addorupdate")
	public ModelAndView addPage( ) {
		ModelAndView page=new ModelAndView( "/picture/picture-addOrUpdatePage" );
		return page;
	}

	/**
	 * 修改页面
	 *
	 * @param id
	 * @return
	 */
	@ApiImplicitParam(name = "String",value = "图片id",required = true)
	@ApiOperation(value = "修改图片")
	@GetMapping("/addorupdate/{id}")
	public ModelAndView updatePage( @PathVariable("id") String id ) {
		ModelAndView page=new ModelAndView( "/picture/picture-addOrUpdatePage" );
		Picture picture=pictureService.selectByPK( id );
		page.addObject( "data",JSON.toJSONString( picture ) );
		return page;
	}

	/**
	 * Picture分页数据接口
	 *
	 * @param par 带有查询参数的对象
	 * @return
	 */
	@GetMapping
	public AjaxResult picture( PicturePar par ) {
		par.setQuerySchema( querySchema );
		try {
			if(par.getPagenation( )) {
				PageInfo< Picture > list=pictureService.queryPagingData( par );
				return AjaxResult.getPageHelperTableResult( list );
			}else {
				List< Picture > list=pictureService.queryAllData( par );
				return AjaxResult.getSuccessResult( list );
			}
		} catch(Exception e) {
			log.error( "数据查询出错，参数："+par.toString( ),e );
			return AjaxResult.getErrorResult( e.getMessage( ) );
		}
	}

	/**
	 * Picture 单个数据的获取
	 *
	 * @param id Picture主键
	 * @return
	 */
	@GetMapping("detail")
	public AjaxResult getPictureById( String id ) {
		Picture picture=pictureService.selectByPK( id );
		//需要使用redis来缓存了，不然没法改盘符中的文件
		//保存原来的图片名称,并设置有效期
		redisTemplate.opsForValue( ).set( picture.getId( ),picture.getPictureName( ),60*60*60,TimeUnit.MINUTES );
		return new AjaxResult( picture );
	}

	/**
	 * Picture 的新增
	 *
	 * @param par
	 * @return
	 */
	@PostMapping
	public AjaxResult addPicture( PicturePar par ) {
		if(!UpdateSchema.checkAddOrUpdate( par,updateSchema )) return AjaxResult.getMissingParamResult( );
		try {
			Picture model=BeanCopyUtil.copyConvey( par,Picture.class );
			pictureService.insertModel( model );
			return new AjaxResult( );
		} catch(Exception e) {
			log.error( "新增操作出错，参数：[{}] ",par.toString( ),e );
			return AjaxResult.getErrorResult( e.getMessage( ) );
		}
	}

	/**
	 * Picture 的修改
	 *
	 * @return
	 */
	@PutMapping("/{id}")
	public AjaxResult updatePicture( @PathVariable("id") String id,PicturePar par ) {
		if(!UpdateSchema.checkAddOrUpdate( par,updateSchema )) return AjaxResult.getMissingParamResult( );
		try {
			Picture model=BeanCopyUtil.copyConvey( par,Picture.class );
			pictureService.updateModel( model );
			// TODO setId
			return new AjaxResult( );
		} catch(Exception e) {
			log.error( "更新操作出错，参数：[{}]",par.toString( ),e );
			return AjaxResult.getErrorResult( e.getMessage( ) );
		}
	}

	/**
	 * 根据ids集合进行删除
	 * 使用默认的分割符号“,”
	 *
	 * @param ids
	 * @return
	 */
	@DeleteMapping("/{ids}")
	public AjaxResult deleteByIds( @PathVariable("ids") String ids ) {
		if(EmptyUtil.isHaveEmpty( ids )) return AjaxResult.getMissingParamResult( );
		try {
			List< String > idList=ListUtil.convey( ListUtil.split( ids,PagingConstant.defaultSplit ),String.class );
			pictureService.deleteByIds( idList );
			return new AjaxResult( );
		} catch(Exception e) {
			log.error( "批量删除出错，参数：[{}]",ids,e );
			return AjaxResult.getErrorResult( e.getMessage( ) );
		}
	}

	/**
	 * 加载图片检测的页面
	 *
	 * @return
	 */
	@RequestMapping("test")
	public ModelAndView getPage( ) {
		return new ModelAndView( "/picturetest/picture_page" );
	}

	/**
	 * 接收模型传来的多张图片
	 *
	 * @param files
	 * @return
	 */
	@PostMapping("/uploadResultPic")
	public AjaxResult uploadResultPic( @RequestParam(value="files") MultipartFile[] files,String flag ) {
		if(ArrayUtils.isEmpty( files )) {
			return AjaxResult.getErrorResult( "上传文件不能为空" );
		}
		ResultMsg resultMsg=verifyFileType( files );
		if(Results.ERROR.equals( resultMsg.getState( ) )) {
			redisTemplate.delete( newKeyName );
			return AjaxResult.getErrorResult( resultMsg.getMsg( ) );
		}
		//获取模型的名称
		String modelName=(String) redisTemplate.opsForValue( ).get( newKeyName );
		//创建一个装载图片实体类的集合
		List< Picture > pictures=new ArrayList<>( );
		for(MultipartFile multipartFile: files) {
			ThreadUtil.sleep( 3,TimeUnit.MILLISECONDS );
			try {
				String fileType=FileUtil.getFileType( multipartFile.getOriginalFilename( ) );
				if(!"jpg".equals( fileType ) && !"png".equals( fileType ) && !"tif".equals( fileType )) {
					log.error( "上传文件出错：{}","文件格式错误，必须是.jpg .png .tif类型的文件" );
					pictures.removeAll( pictures );
					redisTemplate.delete( newKeyName );
					return AjaxResult.getErrorResult( "文件格式错误，必须是.jpg .png .tif类型的文件" );
				}

				String pictureName=modelName+"-R-"+multipartFile.getOriginalFilename( ).substring( 10 );
				String path=PictureConstant.PICTURE_ADDRESS_RESULT+FileUtil.dirSperator+pictureName;
				FileUtil.save( multipartFile,path );
				Picture picture=new Picture( );
				File file=new File( path );
		        //计算图片的色块占比率
				double whiteRatio=ImageUtils.getWhiteRatio( file );
				String s=String.valueOf( whiteRatio ).substring( 0,5 );
				picture.setProportion( s+"%" );
				picture.setPictureAddress( PictureConstant.PICTURE_ADDRESS_RESULT );
				picture.setPictureType( PictureConstant.PICTURE_TYPE_RESULT );
				picture.setPictureName( pictureName );
				pictureService.insertModel( picture );
			} catch(Exception e) {
				log.error( "上传文件出错：{}",e.getMessage( ) );
				redisTemplate.delete( newKeyName );
				return AjaxResult.getErrorResult( "上传文件出错" );
			}
		}

		if(flag!=null) {
			redisTemplate.delete( newKeyName );
		}
		return new AjaxResult( );
	}

	/**
	 * 系统传来的检测图片
	 *
	 * @param file_data
	 * @return
	 */
	@RequestMapping("/uploadMulti")
	public AjaxResult uploadMulti( @RequestParam MultipartFile[] file_data ) {
		if(ArrayUtils.isEmpty( file_data )) {
			return AjaxResult.getErrorResult( "上传文件不能为空" );
		}
		//创建一个装载图片实体类的集合
		List< Picture > pictures=new ArrayList<>( );
		for(MultipartFile multipartFile: file_data) {
			ThreadUtil.sleep( 3,TimeUnit.MILLISECONDS );
			try {
				String fileType=FileUtil.getFileType( multipartFile.getOriginalFilename( ) );
				if("jpg".equals( fileType ) || "png".equals( fileType ) || "tif".equals( fileType )) {
					String name="historical_"+BaseClass.getUUIDWithoutConnector( ).substring( 1,15 )+".jpg";
					String path=PictureConstant.PICTURE_ADDRESS_HOSTORICAL+FileUtil.dirSperator+name;
					FileUtil.save( multipartFile,path );
					Picture picture=new Picture( );
					picture.setPictureAddress( PictureConstant.PICTURE_ADDRESS_HOSTORICAL );
					picture.setPictureType( PictureConstant.PICTURE_TYPE_HISTORICAL );
					picture.setPictureName( name );
					pictures.add( picture );
				}else {
					log.error( "上传文件出错：{}","文件格式错误，必须是.jpg .png .tif类型的文件" );
					pictures.removeAll( pictures );
					redisTemplate.delete( newKeyName );
					return AjaxResult.getErrorResult( "文件格式错误，必须是.jpg .png .tif类型的文件" );
				}

			} catch(Exception e) {
				log.error( "上传文件出错：{}",e.getMessage( ) );
				redisTemplate.delete( newKeyName );
				return AjaxResult.getErrorResult( "上传文件出错" );
			}
		}

		//调用裁剪图片功能，并进行检测
		String message=testPictures( pictures );
		System.out.println(message );
		return new AjaxResult();
	}

	/**
	 * 调用模型
	 *
	 * @param files
	 * @param modelName
	 * @param redisTemplate
	 * @return
	 */
	private String useModel( List< File > files,String modelName,RedisTemplate redisTemplate ) {
		String s=null;
		try {
			s=PostMultipartUtil.sendPost( PictureConstant.POST_URL,files,modelName,redisTemplate );
		} catch(UnsupportedEncodingException e) {
			e.printStackTrace( );
		}
		return s;
	}

	/**
	 * 图片裁剪
	 *
	 * @param pictures
	 */
	private String testPictures( List< Picture > pictures ) {
		List< File > upPictures=new ArrayList<>( );
		//获取模型的名称
		String modelName=(String) redisTemplate.opsForValue( ).get( newKeyName );
		//对图片进行裁剪
		for(Picture picture: pictures) {
			try {
				Picture resultPicture=new Picture( );
				//生成新的图片名称
				resultPicture.setPictureName( modelName+"-H-"+BaseClass.getUUIDWithoutConnector( ).toString( )
						.substring( 1,15 )+".jpg" );
				PictureUtill.zoomImage( PictureConstant.PICTURE_ADDRESS_HOSTORICAL+FileUtil.dirSperator+picture.getPictureName( ),PictureConstant.PICTURE_ADDRESS_RESULT+FileUtil.dirSperator+resultPicture.getPictureName( ),256,256 );
				resultPicture.setPictureAddress( PictureConstant.PICTURE_ADDRESS_RESULT );
				resultPicture.setPictureType( PictureConstant.PICTURE_TYPE_HISTORICAL );
				//创建一个集合用来保存上传的结果的图片
				File file=new File( PictureConstant.PICTURE_ADDRESS_RESULT+FileUtil.dirSperator+resultPicture.getPictureName( ) );
				upPictures.add( file );
				//生成一个完整的picture并保存
				pictureService.insertModel( resultPicture );
			} catch(Exception e) {
				redisTemplate.delete( newKeyName );
				e.printStackTrace( );
			}
		}

		//调用模型
		String s=useModel( upPictures,modelName+"*"+newKeyName, redisTemplate);
		return s;

	}

	/**
	 * 校验文件类型
	 *
	 * @param file_data
	 * @return
	 */
	private ResultMsg verifyFileType( MultipartFile[] file_data ) {
		ResultMsg resultMsg=new ResultMsg( Results.SUCCESS );
		for(MultipartFile file_datum: file_data) {
			if(!"0".equals( FileTypeUtil.getFileType( file_datum.getOriginalFilename() ) )) {
				resultMsg.setState( Results.ERROR );
				resultMsg.setMsg( "上传文件格式不符合要求" );
			}
		}
		return resultMsg;
	}

	/**
	 * 获取文件保存到本地:文件名+时间戳+文件后缀
	 *
	 * @param name
	 * @return
	 */
	public static String getFileNameWithDate( String name ) {
		return FileUtil.getFileName( name )+FileUtil.createPrefix+DateUtil.dateToString(
				new Date( ),DateUtil.FORMAT_yMdHmsSSS )+FileUtil.fileSperator+FileUtil.getFileType( name );
	}

	/**
	 * 获取历史结果的照片
	 */
	@RequestMapping("resultPictures")
	public ModelAndView getresultPictures( ) {
		return new ModelAndView( "/picturetest/show_pictures" );
	}

	/**
	 * 获取历史检测的照片
	 */
	@RequestMapping("historicalPictures")
	public ModelAndView gethistorPictures( ) {
		return new ModelAndView( "/picturetest/show_pictures_historical" );
	}

	/**
	 * 根据图片类型获取图片的name
	 *
	 * @param picture
	 * @return
	 */
	@RequestMapping("list")
	public AjaxResult getNames( PicturePar picture ) throws Exception {
		picture.setOptiorName( BaseClass.getSessionUserid( ) );
		picture.setQuerySchema( querySchema );
		List< Picture > names=pictureService.queryNames( picture );
		return new AjaxResult( names );
	}

	/**
	 * 根据id 逻辑删除数据库中的相关对象
	 *
	 * @param id
	 * @return
	 */
	@PostMapping("/deleteById")
	public AjaxResult deleteById( String id ) {
		if(EmptyUtil.isHaveEmpty( id )) return AjaxResult.getMissingParamResult( );
		try {
			List< String > ids=new ArrayList<>( );
			ids.add( id );
			pictureService.deleteByIds( ids );
			return new AjaxResult( );
		} catch(Exception e) {
			log.error( "批量删除出错，参数：[{}]",id,e );
			return AjaxResult.getErrorResult( e.getMessage( ) );
		}
	}

	/**
	 * AirportMaintenance 的新增或修改
	 *
	 * @param par
	 * @return
	 */
	@PostMapping("updatePicture")
	public AjaxResult addAirportMaintenance( PicturePar par ) {
		if(!UpdateSchema.checkAddOrUpdate( par,updateSchema )) return AjaxResult.getMissingParamResult( );
		try {
			//根据id的值是否为空来判断进行的程序
			if(!EmptyUtil.isHaveEmpty( par.getId( ) )) {
				Picture model=BeanCopyUtil.copyConvey( par,Picture.class );
				pictureService.updateModel( model );
				return new AjaxResult( );
			}else {
				return AjaxResult.getErrorResult( "参数缺失！" );
			}

		} catch(Exception e) {
			log.error( "新增操作出错，参数：[{}] ",par.toString( ),e );
			return AjaxResult.getErrorResult( e.getMessage( ) );
		}
	}

	/**
	 * 模型名字获取
	 *
	 * @param allmodel
	 * @return
	 * @throws InterruptedException
	 */
	@RequestMapping("realAdd")
	public AjaxResult realAdd( String allmodel,String dataList) throws InterruptedException {
		if(!EmptyUtil.isHaveEmpty( allmodel )) {
			newKeyName=BaseClass.getSessionUserid( )+"-"+allmodel;
			//防止名字被覆盖，这一块感觉无法满足多个用户同时登录操作的需求标识不够区分对modelname这个字段多携带一项信息用户id
			String modelName=(String) redisTemplate.opsForValue( ).get( newKeyName );
			while(modelName!=null && !"".equals( modelName )) {
				Thread.sleep( 3000 );
				modelName=(String) redisTemplate.opsForValue( ).get( newKeyName );
			}

			redisTemplate.opsForValue( ).set( newKeyName,allmodel,30,TimeUnit.MINUTES );
			redisTemplate.opsForValue( ).set( "dataListName",dataList,30,TimeUnit.MINUTES );
			return new AjaxResult( );
		}else {
			return AjaxResult.getErrorResult( "模型名字不能为空！" );
		}

	}

	/**
	 * 图片下载
	 * ids   需要下载的图片的id集合
	 */
	@GetMapping("/downLoadPictures/{names}")
	public void downLoadPicturesByIds( HttpServletRequest request,HttpServletResponse resp,@PathVariable("names") String names ) throws Exception {
		int times=1;
		//设置自旋锁
		if(redisTemplate.opsForValue( ).get( "time" )==null) {
			redisTemplate.opsForValue( ).set( "time","first" );
		}else {
			Object time=redisTemplate.opsForValue( ).get( "time" );
			while(time!=null) {
				times++;
				Thread.sleep( 3000 );
				time=redisTemplate.opsForValue( ).get( "time" );
			}
			redisTemplate.opsForValue( ).set( "time","first" );
		}

		String s=names.replaceAll( "!","." );
		List< String > idList=ListUtil.convey( ListUtil.split( s,PagingConstant.defaultSplit ),String.class );
		for(String pictureName: idList) {
			//使用字节输入流加载进内存
			FileInputStream is=new FileInputStream( PictureConstant.PICTURE_ADDRESS_HOSTORICAL+File.separator+pictureName );
			//处理中文文件名问题
			byte[] bytes=pictureName.getBytes( "UTF-8" );
			String newfilename=new String( bytes,"iso-8859-1" );
			//设置响应头
			resp.setHeader( "content-disposition","attachment; filename="+newfilename );
			//获取响应对象自带的字节输出流
			ServletOutputStream os=resp.getOutputStream( );
			byte[] data=new byte[1024];
			int len;
			while((len=is.read( data ))!=-1) {
				os.write( data,0,len );
			}
			is.close( );
			os.close( );
			redisTemplate.delete( "time" );
		}


	}

}


